/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DaveSexton.DocProject.Engine;
using System.IO;

namespace DaveSexton.DocProject.Sandcastle
{
	internal sealed class GenerateFrameworkReflectionDataBuildStep : BuildStep<SandcastleBuildEngine>
	{
		#region Public Properties
		public override string Name
		{
			get
			{
				return string.Format(System.Globalization.CultureInfo.CurrentCulture,
					Resources.Text.GenerateFrameworkReflectionDataStepName, dataFolderName);
			}
		}
		#endregion

		#region Private / Protected
		private readonly string dataFolderName, target;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="GenerateFrameworkReflectionDataBuildStep" /> class.
		/// </summary>
		public GenerateFrameworkReflectionDataBuildStep(SandcastleBuildEngine engine, string target, string dataFolderName)
			: base(engine)
		{
			this.target = target;
			this.dataFolderName = dataFolderName;

			RunInBackground = true;
		}
		#endregion

		#region Methods
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "DaveSexton.DocProject.BuildContext.TraceLine(System.String)")]
		protected override void ExecuteInternal(BuildContext context)
		{
			BuildStepCollection steps = new BuildStepCollection(Engine);

			context.TraceLine();
			context.TraceLine("Preparing for the generation of .NET framework reflection data...");
			context.TraceLine();

			AddAssembliesInPath(context, steps, @"%WINDIR%\Microsoft.NET\Framework\v2.0.50727\", "2.0", ".NET 2.0 Framework", false);

			if (context.Canceled)
				return;

			AddAssembliesInPath(context, steps, @"%WINDIR%\Microsoft.NET\Framework\v3.0\", "3.0", ".NET 3.0 Framework", true);

			if (context.Canceled)
				return;

			AddAssembliesInPath(context, steps, @"%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\", "3.0", ".NET 3.0 Framework", false);

			if (context.Canceled)
				return;

			AddAssembliesInPath(context, steps, @"%WINDIR%\Microsoft.NET\Framework\v3.5\", "3.5", ".NET 3.5 Framework", true);

			if (context.Canceled)
				return;

			AddAssembliesInPath(context, steps, @"%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5\", "3.5", ".NET 3.5 Framework", false);

			if (context.Canceled)
				return;

			context.TraceLine();
			context.TraceLine("Starting generation of .NET Framework reflection data files...");

			context.ExecuteOutOfBand(steps);
		}

		private void AddAssembliesInPath(BuildContext context, BuildStepCollection steps, string path, string version, string versionTitle, bool recursive)
		{
			path = Environment.ExpandEnvironmentVariables(path);

			if (!Directory.Exists(path))
				return;

			context.TraceLine();
			context.TraceLine("Preparing for " + versionTitle + "...");
			context.TraceLine("(" + path + ")");
			context.TraceLine();

			string temp = Path.GetTempPath();
			string versionTarget = Path.Combine(target, version);

			if (!Directory.Exists(versionTarget))
				Directory.CreateDirectory(versionTarget);

			foreach (string assembly in Directory.GetFiles(path, "*.dll", (recursive) ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly))
			{
				string name = Path.GetFileNameWithoutExtension(assembly);
				string tempFile = Path.Combine(temp, name + ".org");

				context.TraceLine("\t" + assembly);

				steps.AddExternalProcess(true, Engine.Settings.MRefBuilder, "\"" + assembly + "\"", "/out:\"" + tempFile + "\"");

				Engine.AddDocModelStep(steps, true, tempFile, Path.Combine(versionTarget, name + ".xml"),
					Engine.Settings.Presentation.GuidFileNamesTransformation, false);
			}
		}

		protected override void CancelInternal(BuildContext context)
		{
			// no action is required because this step simply delegates its work to other build steps that handle cancelation
		}
		#endregion
	}
}
